package authservice

import (
	"context"
	"gitee.com/go-mid/auth/internal/component"
	"gitee.com/go-mid/auth/internal/dao"
	"gitee.com/go-mid/auth/internal/entity"
	"gitee.com/go-mid/infra/xlog"
	"gitee.com/go-mid/infra/xsql/xdb"
	"gitee.com/go-mid/infra/xtime"
	"github.com/jinzhu/copier"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"time"
)

type GetAuthTokenReq struct {
	ID int64 `json:"id"` //  登录认证信息唯一标识
} //@name 获取登录认证信息入参

type AuthTokenInfo struct {
	ID                 int64  `json:"id" bdb:"id"`                                     //
	Ct                 int64  `json:"ct" bdb:"ct"`                                     //创建时间
	Ut                 int64  `json:"ut" bdb:"ut"`                                     //修改时间
	UserID             int64  `json:"user_id" bdb:"user_id"`                           //用户id
	Appid              int64  `json:"appid" bdb:"appid"`                               //appid
	AuthType           int32  `json:"auth_type" bdb:"auth_type"`                       //认证类型。
	AccessToken        string `json:"access_token" bdb:"access_token"`                 //accesstoken
	AccessTokenExpire  int64  `json:"access_token_expire" bdb:"access_token_expire"`   //atk过期时间
	RefreshToken       string `json:"refresh_token" bdb:"refresh_token"`               //刷新token
	RefreshTokenExpire int64  `json:"refresh_token_expire" bdb:"refresh_token_expire"` //rtk过期时间
	ClientInfo         string `json:"client_info" bdb:"client_info"`                   //客户端信息

} //@name 登录认证信息信息

type GetAuthTokenRes struct {
	AuthTokenInfo *AuthTokenInfo `json:"auth_token_info"`
} //@name 获取登录认证信息响应

func (m *AuthServiceImpl) GetAuthToken(ctx context.Context, req *GetAuthTokenReq) (res *GetAuthTokenRes, err error) {
	fun := "AuthServiceImpl.GetAuthToken -->"
	st := xtime.NewTimeStat()
	defer func() {
		xlog.Infow(ctx, fun, "durationMs", st.Millisecond(), "req", req, "res", res, "err", err)
	}()
	//这里 不能是空指针
	item, err := dao.GetAuthToken(ctx, component.XDBAuth, req.ID)
	if err != nil {
		xlog.Warnf(ctx, "%s dao.GetAuthToken err: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	if item == nil {
		return nil, nil
	}
	res = &GetAuthTokenRes{
		AuthTokenInfo: m.toAuthTokenInfo(ctx, item),
	}
	return
}

func (m *AuthServiceImpl) toAuthTokenInfo(ctx context.Context, item *entity.AuthToken) *AuthTokenInfo {
	if item == nil {
		return nil
	}
	var info AuthTokenInfo
	copier.Copy(&info, item)
	return &info
}
func (m *AuthServiceImpl) toAuthTokenInfos(ctx context.Context, items []*entity.AuthToken) []*AuthTokenInfo {
	var infos = make([]*AuthTokenInfo, 0)
	for _, item := range items {
		infos = append(infos, m.toAuthTokenInfo(ctx, item))
	}
	return infos
}

type ListAuthTokenReq struct {
	Offset    int64 `json:"offset"`     // 下一页游标
	Limit     int64 `json:"limit"`      // 每页条数
	WithTotal bool  `json:"with_total"` // 是否查询总量
} //@name 查询登录认证信息入参

type ListAuthTokenRes struct {
	Items  []*AuthTokenInfo `json:"items"`
	Offset int64            `json:"offset"`
	More   bool             `json:"more"`
	Total  int              `json:"total"`
} //@name 查询登录认证信息响应

func (m *AuthServiceImpl) ListAuthToken(ctx context.Context, req *ListAuthTokenReq) (res *ListAuthTokenRes, err error) {
	fun := "AuthServiceImpl.ListAuthToken -->"
	st := xtime.NewTimeStat()
	defer func() {
		xlog.Infow(ctx, fun, "durationMs", st.Millisecond(), "req", req, "res", res, "err", err)
	}()
	var items []*entity.AuthToken
	var offset = req.Offset
	var limit = req.Limit
	if offset < 0 {
		offset = 0
	}
	if limit < 1 || limit > 1000 {
		limit = 1000
	}
	var where = map[string]interface{}{
		//	todo where条件
		"_limit":   []int64{offset, limit + 1},
		"_orderby": "ct desc",
	}
	err = component.XDBAuth.Select(ctx, entity.AuthTokenTable, where, &items)
	if err != nil {
		xlog.Warnf(ctx, "%s select err: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	var more bool
	if len(items) > int(limit) {
		items = items[0:limit]
		more = true
	}
	offset = offset + int64(len(items))
	var total int
	if req.WithTotal {
		delete(where, "_limit")
		delete(where, "_orderby")
		cnt, err := component.XDBAuth.SelectCount(ctx, entity.AuthTokenTable, where)
		if err != nil {
			xlog.Warnf(ctx, "%s count err: req: %v, err: %v", fun, req, err)
			err = status.Error(codes.Internal, err.Error())
			return nil, err
		}
		total = cnt
	}
	res = &ListAuthTokenRes{
		Items:  m.toAuthTokenInfos(ctx, items),
		Offset: offset,
		More:   more,
		Total:  total,
	}
	return
}

type AddAuthTokenReq struct {
	UserID             int64  `json:"user_id" bdb:"user_id"`                           //用户id
	Appid              int64  `json:"appid" bdb:"appid"`                               //appid
	AuthType           int32  `json:"auth_type" bdb:"auth_type"`                       //认证类型。
	AccessToken        string `json:"access_token" bdb:"access_token"`                 //accesstoken
	AccessTokenExpire  int64  `json:"access_token_expire" bdb:"access_token_expire"`   //atk过期时间
	RefreshToken       string `json:"refresh_token" bdb:"refresh_token"`               //刷新token
	RefreshTokenExpire int64  `json:"refresh_token_expire" bdb:"refresh_token_expire"` //rtk过期时间
	ClientInfo         string `json:"client_info" bdb:"client_info"`                   //客户端信息

} //@name 添加登录认证信息入参

type AddAuthTokenRes struct {
	ID int64 `json:"id"`
} //@name 添加登录认证信息入参

func (m *AuthServiceImpl) AddAuthToken(ctx context.Context, req *AddAuthTokenReq) (res *AddAuthTokenRes, err error) {
	fun := "AuthServiceImpl.AddAuthToken -->"
	st := xtime.NewTimeStat()
	defer func() {
		xlog.Infow(ctx, fun, "durationMs", st.Millisecond(), "req", req, "res", res, "err", err)
	}()
	var item entity.AuthToken
	copier.Copy(&item, req)
	//todo  构建inert对象
	now := time.Now().Unix()
	item.Ct = now
	item.Ut = now
	ups, err := xdb.BuildDbSqlMap(ctx, &item, false)
	if err != nil {
		xlog.Warnf(ctx, "%s build sql err: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	newID, err := component.XDBAuth.Insert(ctx, entity.AuthTokenTable, []map[string]interface{}{
		ups,
	})
	if err != nil {
		xlog.Errorf(ctx, "%s add db error: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	res = &AddAuthTokenRes{
		ID: int64(newID),
	}
	return
}

type UpdateAuthTokenReq struct {
	ID                 int64  `json:"id" bdb:"id"`                                     //
	UserID             int64  `json:"user_id" bdb:"user_id"`                           //用户id
	Appid              int64  `json:"appid" bdb:"appid"`                               //appid
	AuthType           int32  `json:"auth_type" bdb:"auth_type"`                       //认证类型。
	AccessToken        string `json:"access_token" bdb:"access_token"`                 //accesstoken
	AccessTokenExpire  int64  `json:"access_token_expire" bdb:"access_token_expire"`   //atk过期时间
	RefreshToken       string `json:"refresh_token" bdb:"refresh_token"`               //刷新token
	RefreshTokenExpire int64  `json:"refresh_token_expire" bdb:"refresh_token_expire"` //rtk过期时间
	ClientInfo         string `json:"client_info" bdb:"client_info"`                   //客户端信息

} //@name 修改登录认证信息入参

type UpdateAuthTokenRes struct {
} //@name 修改登录认证信息响应

func (m *AuthServiceImpl) UpdateAuthToken(ctx context.Context, req *UpdateAuthTokenReq) (res *UpdateAuthTokenRes, err error) {
	fun := "AuthServiceImpl.UpdateAuthToken -->"
	st := xtime.NewTimeStat()
	defer func() {
		xlog.Infow(ctx, fun, "durationMs", st.Millisecond(), "req", req, "res", res, "err", err)
	}()
	var item entity.AuthToken
	copier.Copy(&item, req)
	now := time.Now().Unix()
	item.Ut = now
	ups, err := xdb.BuildSqlMap(ctx, &item, xdb.BuildOption{
		OmitZero:       true,
		ExcludeColumns: []string{"id"},
	})
	if err != nil {
		xlog.Warnf(ctx, "%s build sql err: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	_, err = component.XDBAuth.Update(ctx, entity.AuthTokenTable, map[string]interface{}{
		"id": req.ID,
	}, ups)
	if err != nil {
		xlog.Errorf(ctx, "%s update db error: req: %v, err: %v", fun, req, err)
		err = status.Error(codes.Internal, err.Error())
		return
	}
	res = &UpdateAuthTokenRes{}
	return
}

type UpsertAuthTokenReq struct {
	ID                 int64  `json:"id" bdb:"id"`                                     //
	UserID             int64  `json:"user_id" bdb:"user_id"`                           //用户id
	Appid              int64  `json:"appid" bdb:"appid"`                               //appid
	AuthType           int32  `json:"auth_type" bdb:"auth_type"`                       //认证类型。
	AccessToken        string `json:"access_token" bdb:"access_token"`                 //accesstoken
	AccessTokenExpire  int64  `json:"access_token_expire" bdb:"access_token_expire"`   //atk过期时间
	RefreshToken       string `json:"refresh_token" bdb:"refresh_token"`               //刷新token
	RefreshTokenExpire int64  `json:"refresh_token_expire" bdb:"refresh_token_expire"` //rtk过期时间
	ClientInfo         string `json:"client_info" bdb:"client_info"`                   //客户端信息

} //@name 添加或修改登录认证信息入参

type UpsertAuthTokenRes struct {
	ID int64 `json:"id"`
} //@name 添加或修改登录认证信息响应

func (m *AuthServiceImpl) UpsertAuthToken(ctx context.Context, req *UpsertAuthTokenReq) (res *UpsertAuthTokenRes, err error) {
	fun := "AuthServiceImpl.UpsertAuthToken -->"
	st := xtime.NewTimeStat()
	defer func() {
		xlog.Infow(ctx, fun, "durationMs", st.Millisecond(), "req", req, "res", res, "err", err)
	}()
	if req.ID > 0 {
		var upReq UpdateAuthTokenReq
		copier.Copy(&upReq, req)
		_, err = m.UpdateAuthToken(ctx, &upReq)
		if err != nil {
			xlog.Warnf(ctx, "%s UpdateAuthToken err: req: %v, err: %v", fun, req, err)
			return
		}
		res = &UpsertAuthTokenRes{
			ID: req.ID,
		}
		return
	}
	var addReq AddAuthTokenReq
	copier.Copy(&addReq, req)
	addRes, err := m.AddAuthToken(ctx, &addReq)
	if err != nil {
		xlog.Warnf(ctx, "%s AddAuthToken err: req: %v, err: %v", fun, req, err)
		return
	}
	res = &UpsertAuthTokenRes{
		ID: addRes.ID,
	}
	return
}
